package com.zj.baseproxy.interfaces.impl;

import com.zj.baseproxy.annotation.Scan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.beans.Introspector;
import java.util.NoSuchElementException;

/**
 * bean名称生成器
 *
 * @author arthur_zhou
 * @date 2023/10/9 14:30
 */
public class BeanNameGeneratorImpl implements BeanNameGenerator {

    private static final Logger log = LoggerFactory.getLogger(BeanNameGeneratorImpl.class);

    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        if (definition instanceof AnnotatedBeanDefinition) {
            return determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
        }
        // 用类名作为bean名称
        return buildDefaultBeanName(definition);
    }

    /**
     * 根据注释确定Bean名称
     *
     * @param definition 定义的注解
     * @return bean名称
     */
    private String determineBeanNameFromAnnotation(AnnotatedBeanDefinition definition) {
        AnnotationMetadata metadata = definition.getMetadata();
        MergedAnnotations annotations = metadata.getAnnotations();
        MergedAnnotation<Scan> scanMergedAnnotation = annotations.get(Scan.class);
        String value = null;
        try {
            value = scanMergedAnnotation.getString("value");
        } catch (NoSuchElementException e) {
            log.warn("ck bean生成失败", e);
        }
        return StringUtils.isEmpty(value) ? buildDefaultBeanName(definition) : value;
    }

    /**
     * Derive a default bean name from the given bean definition.
     * <p>The default implementation simply builds a decapitalized version
     * of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
     * <p>Note that inner classes will thus have names of the form
     * "outerClassName.InnerClassName", which because of the period in the
     * name may be an issue if you are autowiring by name.
     *
     * @param definition the bean definition to build a bean name for
     * @return the default bean name (never {@code null})
     */
    protected String buildDefaultBeanName(BeanDefinition definition) {
        String beanClassName = definition.getBeanClassName();
        Assert.state(beanClassName != null, "No bean class name set");
        String shortClassName = ClassUtils.getShortName(beanClassName);
        return Introspector.decapitalize(shortClassName);
    }
}
